#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <string.h>
#include "gpio.h"
#include "gpiotimer.h"


// gpio sysfs path
#define GPIO_CLASS_PATH "/sys/class/gpio"

int export_fd = -1;
int unexport_fd = -1;

// whether export file and unexport file is opened
int export_opened = 0;

// how many port opened
int ref = 0;

int gpio_open(struct GPIO* gpio, int portnum)
{
	char filename[50];




	// open export
	// if first time use export file then open it
	if(0 == ref) {
		sprintf(filename, "%s/export", GPIO_CLASS_PATH);
		export_fd = open(filename, O_WRONLY);
		if(-1 == export_fd) {
			perror("open export_fd");
		}

		// open unexport
		sprintf(filename, "%s/unexport", GPIO_CLASS_PATH);
		unexport_fd = open(filename, O_WRONLY);
		if(-1 == unexport_fd) {
			perror("open unexport_fd");
		}

		export_opened = 1;
	}

	ref++;

	gpio->export_fd = export_fd;
	gpio->unexport_fd = unexport_fd;
	gpio->portnum = portnum;

	// open a gpio port
	sprintf(filename, "%d", portnum);
	if(-1 == write(gpio->export_fd, filename, 5)) {
		perror("write export_fd");
	}

	// open direction
	sprintf(filename, "%s/gpio%d/direction", GPIO_CLASS_PATH, portnum);
	gpio->direction_fd = open(filename, O_WRONLY);
	if(-1 == gpio->direction_fd) {
		perror("open direction_fd");
	}

	// open value_fd
	//char filename[60]; // can't too small or it will overrflow cause Bus Error
	sprintf(filename, "%s/gpio%d/value", GPIO_CLASS_PATH, gpio->portnum);
	gpio->value_fd = open(filename, O_WRONLY);


	return 1; // need change here
}

void gpio_close(struct GPIO* gpio)
{
	char buf[10];
	//close(gpio->value_fd);
	//close(gpio->direction_fd);

	sprintf(buf, "%d", gpio->portnum);
	write(gpio->unexport_fd, buf, 10);


	ref--;
	if(0 == ref) {
		close(unexport_fd);
		unexport_fd = -1;

		close(export_fd);
		export_fd = -1;


		export_opened = 0;
	}


	close(gpio->value_fd);
}

int gpio_set_direction(struct GPIO* gpio, int direction)
{
	int n = -1;

	if(IN == direction) {
		n = write(gpio->direction_fd, "in", 2);
	} else if(OUT == direction) {
		n = write(gpio->direction_fd, "out", 3);
	}
	if(-1 == n) {
		perror("set direction error");
	}

	return n;
}

int gpio_write(struct GPIO* gpio, int value)
{
	int n;
	char buf[10];

	sprintf(buf, "%d", value);

	n = write(gpio->value_fd, buf, 10);
	if(-1 == n) {
		perror("write value to gpio");
	}


	return n;
}

int gpio_read(struct GPIO* gpio)
{
	int n = 0;
	//char buf[5];

	// open value_fd
	char filename[60]; // can't too small or it will overrflow cause Bus Error
	sprintf(filename, "%s/gpio%d/value", GPIO_CLASS_PATH, gpio->portnum);
	gpio->value_fd = open(filename, O_RDONLY);

	if(-1 == gpio->value_fd) {
		perror("open value_fd");
	}

	if(-1 == lseek(gpio->value_fd, 0, SEEK_SET)) {
		perror("lseek value_fd");
	}

	// read value
	if(-1 == read(gpio->value_fd, &n, 1)) {
		perror("read gpio value");
		return -1;
	}

	n -= '0';

	// don't need close, seems it will close automatically

	return n;
}

void gpio_hold(struct GPIO* gpio, int value, int msec)
{
	gpiotimer_hold(gpio, value, msec);
}
